home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 May / EnigmA AMIGA RUN 18 (1997)(G.R. Edizioni)(IT)[!][issue 1997-05][EAR-CD II].iso / ghost / gs403src_gs.lha / gs4.03 / gspmdrv.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  35KB  |  1,253 lines

  1. /* Copyright (C) 1994 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gspmdrv.c */
  20. /* Presentation Manager driver for Ghostscript */
  21. /* Written by Russell Lang */
  22.  
  23. /* To display output from os2pm driver: */
  24. /*   gspmdrv -d id_string */
  25. /* To display BMP file (used for testing display code) */
  26. /*   gspmdrv -b filename.bmp */
  27.  
  28. #define INCL_DOS
  29. #define INCL_WIN
  30. #define INCL_GPI
  31. #include <os2.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <sys/emxload.h>
  36. #include "gspmdrv.h"
  37. #include "gdevpm.h"
  38.  
  39. #ifndef min
  40. #define min(x,y)  ( (x) < (y) ? (x) : (y) )
  41. #endif
  42. #ifndef max
  43. #define max(x,y)  ( (x) > (y) ? (x) : (y) )
  44. #endif
  45.  
  46. HEV update_event_sem;
  47. HMTX bmp_mutex_sem;
  48.  
  49. /* bitmap details */
  50. typedef struct tagBM {
  51.     BOOL    valid;
  52.     BOOL    old_bmp;    /* bitmap type */
  53.     PBITMAPINFO2 pbmi;        /* pointer to bitmap info */
  54.     PBYTE    bits;        /* pointer to bitmap bits */
  55.     int        width;
  56.     int        height;
  57.     int        planes;
  58.     int        depth;
  59.     int        palsize;
  60.     int     palimportant;
  61.     int        old_width;
  62.     int        old_height;
  63.     int        old_planes;
  64.     int        old_depth;
  65.     int        old_palsize;
  66.     int        old_palimportant;
  67. } BMAP;
  68.  
  69. typedef struct tagDISPLAY {
  70.     LONG    planes;
  71.     LONG    bitcount;
  72.     LONG    hasPalMan;    /* Palette Manager */
  73.     BOOL    hpal_exists;
  74.     HPAL    hpal;
  75. } DISPLAY;
  76.  
  77. /* options that are saved in INI file */
  78. typedef struct tagOPTIONS {
  79.     POINTL    img_origin;
  80.     POINTL    img_size;
  81.     BOOL    img_max;
  82. } OPTIONS;
  83. #define CW_USEDEFAULT 32768
  84.  
  85.  
  86. BMAP bitmap;
  87. DISPLAY display;
  88. OPTIONS option;
  89. PBYTE bbuffer;        /* for BMP file display */
  90. POINTL scroll_pos;    /* not used */    /* not used */
  91. ULONG os_version;
  92. char *section = "Ghostscript Image";
  93.  
  94. HAB hab;        /* Anchor Block */
  95. HWND hwnd_frame;
  96. HWND hwnd_bmp;
  97. HWND hwnd_gs;        /* window handle for CMD.EXE that started gs */
  98. TID update_tid;
  99. #define WM_GSUPDATE WM_USER+1
  100. #define SB_TOP 20
  101. #define SB_BOTTOM 21
  102.  
  103.  
  104. MRESULT EXPENTRY ClientWndProc(HWND, ULONG, MPARAM, MPARAM);
  105. MRESULT EXPENTRY AboutDlgProc(HWND, ULONG, MPARAM, MPARAM);
  106. APIRET init_window(void);
  107. void fix_sysmenu(HWND);
  108. APIRET restore_window_position(SWP *pswp);
  109. BOOL scan_bitmap(BMAP *pbm);
  110. void read_profile(void);
  111. void write_profile(void);
  112. APIRET init_display(int argc, char *argv[]); 
  113. APIRET init_bitmap(int argc, char *argv[]); 
  114. void copy_clipboard(void);
  115. HBITMAP make_bitmap(BMAP *pbm, ULONG left, ULONG bottom, ULONG right, ULONG top, ULONG depth);
  116.  
  117. void
  118. debugbeep(int type)
  119. {
  120. #ifdef DEBUG
  121. int i;
  122. /* current debug beeps are: */
  123. /* 1. Null handle PS */
  124. /* 2. make_bitmap() failed */
  125. /* 3. GpiDrawBits() or WinDrawBitmap() failed */
  126. /* 4. Null handle PS from WinBeginPaint() */
  127.     for (i=0; i<type; i++) {
  128.         DosBeep(400+100*type,50);
  129.         DosSleep(50);
  130.     }
  131. #endif
  132. }
  133.  
  134.  
  135. /* display message */
  136. int
  137. message_box(char *str, int icon)
  138. {
  139.       return WinMessageBox(HWND_DESKTOP, hwnd_frame ? hwnd_frame : HWND_DESKTOP, 
  140.         str, "gspmdrv.exe", 0, icon | MB_MOVEABLE | MB_OK);
  141. }
  142.  
  143. void error_message(char *str)
  144. {
  145.       WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, str, "gspmdrv.exe", 0, MB_MOVEABLE | MB_ICONHAND | MB_OK);
  146.     WinPostMsg(hwnd_frame, WM_QUIT, MPFROMLONG(0), MPFROMLONG(0));
  147. }
  148.  
  149. /* Update thread */
  150. /* This thread waits for the update event semaphore from gs.exe */
  151. /* then generates a WM_PAINT message for the bitmap */
  152. /* This thread must NOT call C library functions */
  153. VOID APIENTRY update_func(ULONG unused)
  154. {
  155.     APIRET rc;
  156.     BOOL flag;
  157.     ULONG count;
  158.     unused = unused;    /* to shut up warning */
  159.     while (!DosQueryEventSem(update_event_sem, &count)) {
  160.         /* loop while semaphore exists */
  161.         DosWaitEventSem(update_event_sem, SEM_INDEFINITE_WAIT);
  162.         DosResetEventSem(update_event_sem, &count);
  163.         WinPostMsg(hwnd_bmp, WM_GSUPDATE, MPFROMLONG(0), MPFROMLONG(0));
  164.     }
  165. }
  166.  
  167. VOID APIENTRY exit_func(ULONG code)
  168. {
  169.     write_profile();
  170.     DosCloseEventSem(update_event_sem);
  171.     DosCloseMutexSem(bmp_mutex_sem);
  172.     DosFreeMem((PVOID)bitmap.pbmi);
  173.     DosExitList(EXLST_EXIT, 0);
  174.     code = code;    /* to shut up warning */
  175. }
  176.  
  177. void
  178. find_hwnd_gs(char *gsid)
  179. {
  180. ULONG ulCount;
  181. ULONG ulLength;
  182. ULONG pBase;
  183. ULONG cbBuf;
  184. PSWBLOCK pswblk;
  185. PSWENTRY pswentry;
  186. SWCNTRL *pswc;
  187. int i;
  188. ULONG pid;
  189. char buf[256];
  190. char *p, *s;
  191.     PTIB pptib;
  192.     PPIB pppib;
  193.  
  194.     /* extract gs pid from command line id */
  195.     strcpy(buf, gsid);
  196.     for (p=buf; *p && *p!='_';p++)
  197.         ;
  198.     *p++='\0';
  199.     s = p;
  200.     for (p=buf; *p && *p!='_';p++)
  201.         ;
  202.     *p='\0';
  203.     pid = atoi(s);    /* pid is Process ID of CMD.EXE that started gsos2.exe */
  204.     
  205.     ulCount = WinQuerySwitchList(hab, NULL, 0);    /* get num of items */
  206.     cbBuf = (ulCount * sizeof(SWENTRY)) + sizeof(HSWITCH);
  207.     pswblk = (PSWBLOCK) malloc(cbBuf+32768);
  208.     ulCount = WinQuerySwitchList(hab, pswblk, cbBuf);    /* get num of items */
  209.     for (i=0; i<ulCount; i++) {
  210.         pswentry = &pswblk->aswentry[i];
  211.         pswc = &pswentry->swctl;
  212.         if (pid == pswc->idProcess)
  213.         hwnd_gs = pswc->hwnd;    /* save window handle */
  214.     }
  215. }
  216.  
  217.  
  218. int
  219. main(int argc, char *argv[])
  220. {
  221.   HMQ hand_mq;        /* message queue */
  222.   QMSG q_mess;        /* message queue */
  223.   APIRET rc = 0;
  224.  
  225.  
  226.   hab = WinInitialize(0);    /* Get the Anchor Block */
  227.  
  228.   hand_mq = WinCreateMsgQueue(hab, 0); /* start a queue */
  229.  
  230.   if (argc < 2) {
  231.     rc = 1;
  232.     error_message("Usage: gspmdrv -d id_string");
  233.   }
  234.  
  235.   if (!rc) {
  236.     if (strcmp(argv[1],"-d")==0) {
  237.     rc = init_display(argc, argv);
  238.     }
  239.     else if (strcmp(argv[1],"-b")==0) {
  240.     rc = init_bitmap(argc, argv);
  241.     }
  242.     else {
  243.     rc = 1;
  244.     error_message("Usage: gspmdrv -d id_string");
  245.     }
  246.   }
  247.  
  248.   if (!rc) {
  249.       rc = DosCreateThread(&update_tid, update_func, 0, 0, 8192);
  250.       if (rc)
  251.             error_message("Failed to create update thread");
  252.   }
  253.  
  254.   if (!rc)
  255.      rc = init_window();
  256.  
  257.   if (!rc)
  258.       WinShowWindow(hwnd_frame, TRUE);
  259.  
  260.   if (!rc) {
  261.       /* keep gspmdrv.exe in memory for number of minutes specified in */
  262.       /* environment variable GS_LOAD */
  263.       _emxload_env("GS_LOAD");
  264.   }
  265.  
  266.   DosExitList(EXLST_ADD, exit_func);
  267.  
  268.   /* message loop */
  269.   while (!rc && WinGetMsg(hab, &q_mess, 0L, 0, 0))
  270.       WinDispatchMsg(hab, &q_mess);
  271.  
  272.   /* Shut down the application window and queue */
  273.   DosKillThread(update_tid);
  274.   WinDestroyWindow(hwnd_frame);
  275.   WinDestroyMsgQueue(hand_mq);
  276.   WinTerminate(hab);
  277.   return rc;
  278. }
  279.  
  280. APIRET
  281. init_window()
  282. {
  283.   ULONG version[3];
  284.   SWP swp;
  285.   APIRET rc = 0;
  286.   ULONG flFlags;    /* Window frame definition */
  287.   unsigned char class[] = "gspmdrvClass";  /* class name */
  288.  
  289.   if (DosQuerySysInfo(QSV_VERSION_MAJOR, QSV_VERSION_REVISION, &version, sizeof(version)))
  290.       os_version = 201000;  /* a guess */
  291.   else {
  292.       os_version = version[0]*10000 + version[1]*100 + version[2];
  293.   }
  294.  
  295.   /* define the frame constants */
  296.   flFlags = FCF_TITLEBAR |    /* have a title bar */
  297.             FCF_SIZEBORDER |    /* have a sizeable window */
  298.             FCF_MINMAX |    /* have a min and max button */
  299.             FCF_SYSMENU |     /* include a system menu */
  300.             FCF_VERTSCROLL |    /* vertical scroll bar */
  301.             FCF_HORZSCROLL |    /* horizontal scroll bar */
  302.         FCF_TASKLIST |    /* show it in window list */
  303.         FCF_ICON;         /* Load icon from resources */
  304.  
  305.     /* save SHELL default size and location */
  306.     rc = WinQueryTaskSizePos(hab, 0, &swp);
  307.     if (rc)
  308.     return rc;
  309.  
  310.     read_profile();
  311.     if ((option.img_size.x==0) || (option.img_size.y==0))
  312.     option.img_size.x = option.img_size.y = CW_USEDEFAULT;
  313.  
  314.     if (!rc) {
  315.     HPS ps = WinGetPS(HWND_DESKTOP);
  316.     HDC hdc = GpiQueryDevice(ps);
  317.     DevQueryCaps(hdc, CAPS_COLOR_PLANES, 1, &display.planes);
  318.     DevQueryCaps(hdc, CAPS_COLOR_BITCOUNT, 1, &display.bitcount);
  319.     DevQueryCaps(hdc, CAPS_ADDITIONAL_GRAPHICS, 1, &display.hasPalMan);
  320.     display.hasPalMan &= CAPS_PALETTE_MANAGER;
  321.     WinReleasePS(ps);
  322.     }
  323.  
  324.     if (!rc) {
  325.     if (!WinRegisterClass(    /* register this window class */
  326.       hab,            /* anchor block */
  327.       (PSZ)class,        /* class name */
  328.       (PFNWP) ClientWndProc,    /* window function */
  329.       CS_SIZEREDRAW |        /* window style */
  330.     CS_MOVENOTIFY,
  331.       0))            /* no storage */
  332.     exit(1);
  333.  
  334.     hwnd_frame = WinCreateStdWindow(
  335.       HWND_DESKTOP,        /* window type */
  336.     0,            /* frame style is not WS_VISIBLE */
  337.       &flFlags,        /* definitions */
  338.       (PSZ)class,        /* client class */
  339.       (PSZ)"Ghostscript Image",  /* title */
  340.       WS_VISIBLE,        /* client style */
  341.       0,            /* resource module */
  342.       ID_GSPMDRV,        /* resource identifier */
  343.       &hwnd_bmp);        /* pointer to client */
  344.  
  345.     fix_sysmenu(hwnd_frame);
  346.     }
  347.     rc = restore_window_position(&swp);
  348.  
  349.     return rc;
  350. }
  351.  
  352.  
  353. void
  354. write_profile(void)
  355. {
  356. char profile[64];
  357.     sprintf(profile, "%d %d", option.img_origin.x, option.img_origin.y);
  358.     PrfWriteProfileString(HINI_USERPROFILE, section, "Origin", profile);
  359.     sprintf(profile, "%d %d", option.img_size.x, option.img_size.y);
  360.     PrfWriteProfileString(HINI_USERPROFILE, section, "Size", profile);
  361.     sprintf(profile, "%d", option.img_max);
  362.     PrfWriteProfileString(HINI_USERPROFILE, section, "Maximized", profile);
  363. }
  364.  
  365. void
  366. read_profile(void)
  367. {
  368. char profile[64];
  369.     PrfQueryProfileString(HINI_USERPROFILE, section, "Origin", "", profile, sizeof(profile));
  370.     if (sscanf(profile,"%d %d", &option.img_origin.x, &option.img_origin.y) != 2) {
  371.         option.img_origin.x = CW_USEDEFAULT;
  372.         option.img_origin.y = CW_USEDEFAULT;
  373.     }
  374.     PrfQueryProfileString(HINI_USERPROFILE, section, "Size", "", profile, sizeof(profile));
  375.     if (sscanf(profile,"%d %d", &option.img_size.x, &option.img_size.y) != 2) {
  376.         option.img_size.x = CW_USEDEFAULT;
  377.         option.img_size.y = CW_USEDEFAULT;
  378.     }
  379.     PrfQueryProfileString(HINI_USERPROFILE, section, "Maximized", "", profile, sizeof(profile));
  380.     if (sscanf(profile,"%d", &option.img_max) != 1)
  381.         option.img_max = 0;
  382. }
  383.  
  384. void
  385. fix_sysmenu(HWND hwnd)
  386. {
  387. MENUITEM mi;
  388. HWND hwndSysMenu;
  389.     if (!WinSendMsg(WinWindowFromID(hwnd, FID_SYSMENU), MM_QUERYITEM, 
  390.         MPFROM2SHORT(SC_SYSMENU, TRUE), MPFROMP(&mi))) {
  391.     message_box("failed getting system menu handle",0); 
  392.     return;
  393.     }
  394.     hwndSysMenu = mi.hwndSubMenu;
  395.     mi.iPosition = MIT_END;
  396.     mi.afStyle = MIS_SEPARATOR;
  397.     mi.afAttribute = 0;
  398.     mi.id = 0;
  399.     mi.hwndSubMenu = 0;
  400.     mi.hItem = 0;
  401.     WinSendMsg(hwndSysMenu, MM_INSERTITEM, MPFROMP(&mi), NULL);
  402.     mi.afStyle = MIS_TEXT;
  403.     mi.id = IDM_ABOUT;
  404.     WinSendMsg(hwndSysMenu, MM_INSERTITEM, MPFROMP(&mi), "About...");
  405.     mi.id = IDM_COPY;
  406.     WinSendMsg(hwndSysMenu, MM_INSERTITEM, MPFROMP(&mi), "Copy");
  407. }
  408.  
  409. APIRET
  410. restore_window_position(SWP *pswp)
  411. {
  412.     SWP swp;
  413.     swp.fl = SWP_MOVE | SWP_SIZE | SWP_SHOW;
  414.  
  415.     if (option.img_max) {
  416.         /* Get maximized frame window position and size. */
  417.     if (!WinGetMaxPosition(hwnd_frame, &swp))
  418.         return 1;
  419.         swp.fl |= SWP_MAXIMIZE ;
  420.     }
  421.     else if ((option.img_size.x   != CW_USEDEFAULT) &&
  422.          (option.img_size.y   != CW_USEDEFAULT) &&
  423.          (option.img_origin.y != CW_USEDEFAULT) &&
  424.          (option.img_origin.y != CW_USEDEFAULT)) {
  425.         LONG cxClientMax ;
  426.         LONG cyClientMax ;
  427.         LONG cyTitleBar ;
  428.         LONG cxSizeBorder ;
  429.         LONG cySizeBorder ;
  430.  
  431.         /* get maximum client window size */
  432.         cxClientMax = WinQuerySysValue (HWND_DESKTOP, SV_CXFULLSCREEN) ;
  433.         cyClientMax = WinQuerySysValue (HWND_DESKTOP, SV_CYFULLSCREEN) ;
  434.         cyTitleBar = WinQuerySysValue (HWND_DESKTOP, SV_CYTITLEBAR) ;
  435.         cxSizeBorder = WinQuerySysValue (HWND_DESKTOP, SV_CXSIZEBORDER) ;
  436.         cySizeBorder = WinQuerySysValue (HWND_DESKTOP, SV_CYSIZEBORDER) ;
  437.         cyClientMax += cyTitleBar ;
  438.  
  439.          /* Make sure x origin is within display boundaries */
  440.          swp.x = option.img_origin.x ;
  441.          if (swp.x < -cxSizeBorder)
  442.              swp.x = 0 ;
  443.  
  444.          /* Make sure window isn't too wide, or negative value */
  445.          swp.cx = option.img_size.x ;
  446.          if (swp.cx >= cxClientMax || swp.cx < 0) {
  447.              swp.cx = cxClientMax ;
  448.              swp.x = 0 ;
  449.          }
  450.  
  451.          if ((swp.x + swp.cx) > (cxClientMax + cxSizeBorder))
  452.              swp.x = cxClientMax + cxSizeBorder - swp.cx ;
  453.  
  454.          /* Make sure y origin is within display boundaries */
  455.          swp.y = option.img_origin.y ;
  456.          if (swp.y < -cySizeBorder)
  457.              swp.y = 0 ;
  458.  
  459.          /* Make sure window isn't too high, or negative value */
  460.          swp.cy = option.img_size.y ;
  461.          if (swp.cy > cyClientMax || swp.cy < 0) {
  462.              swp.cy = cyClientMax ;
  463.              swp.y = 0 ;
  464.          }
  465.  
  466.          if ((swp.y + swp.cy) > (cyClientMax + cySizeBorder))
  467.              swp.y = cyClientMax + cySizeBorder - swp.cy ;
  468.     }
  469.     else { /* No saved position -- use supplied position */
  470.     swp = *pswp;
  471.     option.img_origin.x = swp.x;
  472.     option.img_origin.y = swp.y;
  473.     option.img_size.x = swp.cx;
  474.     option.img_size.y = swp.cy;
  475.     option.img_max = FALSE;
  476.         swp.fl = SWP_MOVE | SWP_SIZE | SWP_SHOW;
  477.     }
  478.  
  479.     if (hwnd_gs)
  480.     swp.fl |= SWP_ZORDER;
  481.     /* Position and size this frame window */
  482.     if (!WinSetWindowPos(hwnd_frame, hwnd_gs,
  483.     swp.x, swp.y, swp.cx, swp.cy, swp.fl))
  484.     return 1;
  485.     return 0;
  486. }
  487.  
  488. APIRET init_display(int argc, char *argv[]) 
  489. {
  490.   char buf[256];
  491.   char name[256];
  492.   APIRET rc = 0;
  493.  
  494.   if (argc != 3) {
  495.     rc = 1;
  496.     error_message("Usage: gspmdrv -d id_string");
  497.   }
  498.  
  499.   find_hwnd_gs(argv[2]);
  500.  
  501.   if (!rc) {
  502.     sprintf(name, SHARED_NAME, argv[2]);
  503.       rc = DosGetNamedSharedMem((PVOID *)&bitmap.pbmi, name, PAG_READ | PAG_WRITE);
  504.       if (rc) {
  505.         sprintf(buf, "Failed to open: bmp shared memory \"%s\" rc = %d", argv[0], rc);
  506.         error_message(buf);
  507.     }
  508.   }
  509.   if (!rc) {
  510.     sprintf(name, SYNC_NAME, argv[2]);
  511.     rc = DosOpenEventSem(name, &update_event_sem);
  512.       if (rc) {
  513.         sprintf(buf, "Failed to open: update event semaphore \"%s\" rc = %d", argv[1], rc);
  514.         error_message(buf);
  515.     }
  516.   }
  517.   if (!rc) {
  518.     sprintf(name, MUTEX_NAME, argv[2]);
  519.     rc = DosOpenMutexSem(name, &bmp_mutex_sem);
  520.       if (rc) {
  521.         sprintf(buf, "Failed to open: bmp mutex semaphore \"%s\" rc = %d", argv[1], rc);
  522.         error_message(buf);
  523.     }
  524.   }
  525.  
  526.   if (!rc) {
  527.       scan_bitmap(&bitmap);
  528.     bitmap.valid = TRUE;
  529.   }
  530.  
  531.   return rc;
  532. }
  533.  
  534.  
  535. APIRET init_bitmap(int argc, char *argv[])
  536. {
  537.   char buf[256];
  538.   APIRET rc = 0;
  539.   HFILE hf;
  540.   ULONG action, count, length;
  541.   PBITMAPFILEHEADER2 pbmfh;
  542.  
  543.   if (argc != 3)
  544.     return 1;    /* error - no filename */
  545.   
  546.   /* open bitmap */
  547.   if ( (rc = DosOpen(argv[2], &hf, &action, 0, FILE_NORMAL, FILE_OPEN,
  548.         OPEN_ACCESS_READONLY | OPEN_SHARE_DENYREADWRITE, 0))
  549.     != (APIRET)0) {
  550.     sprintf(buf,"Error opening: %s",argv[2]);
  551.     error_message(buf);
  552.     return rc;
  553.   }
  554.  
  555.   rc = DosSetFilePtr(hf, 0, FILE_END, &length);
  556.   if (rc) {
  557.     sprintf(buf, "failed seeking to EOF: error = %d", rc);
  558.     error_message(buf);
  559.     return rc;
  560.   }
  561.  
  562.   rc = DosSetFilePtr(hf, 0, FILE_BEGIN, &count);
  563.   if (rc) {
  564.     sprintf(buf, "failed seeking to BOF: error = %d", rc);
  565.     error_message(buf);
  566.     return rc;
  567.   };
  568.  
  569.   /* allocate memory for bitmap */
  570.   if ( (rc = DosAllocMem((PPVOID)&bbuffer, length, PAG_READ | PAG_WRITE | PAG_COMMIT))
  571.     != (APIRET)0 ){
  572.     sprintf(buf, "failed allocating memory");
  573.     error_message(buf);
  574.     return rc;
  575.   }
  576.  
  577.   rc = DosRead(hf, bbuffer, length, &count);
  578.   DosClose(hf);
  579.   if (rc) {
  580.     sprintf(buf, "failed reading bitmap, error = %u, count = %u", rc, count);
  581.     error_message(buf);
  582.     return rc;
  583.   }
  584.  
  585.   /* extract some info about bitmap */
  586.   pbmfh = (PBITMAPFILEHEADER2)bbuffer;
  587.   bitmap.pbmi = (PBITMAPINFO2)(&pbmfh->bmp2);
  588.  
  589.   scan_bitmap(&bitmap);
  590.   bitmap.valid = TRUE;
  591.  
  592.   sprintf(buf, "bitmap width = %d, height = %d", bitmap.width, bitmap.height);
  593.   message_box(buf,0);
  594.   return rc;
  595. }
  596.  
  597. #define MAX_PAL_SIZE 256
  598. void
  599. make_palette(BMAP *pbm)
  600. {
  601. ULONG tbl[MAX_PAL_SIZE];
  602. PRGB2 palptr = (PRGB2) ((PBYTE)(pbm->pbmi) + pbm->pbmi->cbFix);
  603. RGB *old_palptr = (RGB *)palptr;
  604. int palcount = pbm->palimportant;
  605. int i;
  606. BOOL old_bmp = (pbm->pbmi->cbFix == sizeof(BITMAPINFOHEADER));
  607.     if (old_bmp) {
  608.     for (i=0; i<palcount; i++) {
  609.         tbl[i] = (old_palptr->bRed<<16) + (old_palptr->bGreen<<8) + (old_palptr->bBlue);
  610.         palptr++;
  611.     }
  612.     }
  613.     else {
  614.     for (i=0; i<palcount; i++) {
  615.         tbl[i] = (palptr->bRed<<16) + (palptr->bGreen<<8) + (palptr->bBlue);
  616.         palptr++;
  617.     }
  618.     }
  619.     if (display.hpal_exists)
  620.     GpiDeletePalette(display.hpal);
  621.     display.hpal = GpiCreatePalette(hab, 0L, LCOLF_CONSECRGB, palcount, tbl);
  622.     display.hpal_exists = TRUE;
  623. }
  624.  
  625.  
  626.  
  627. /* scan bitmap */
  628. /* update bitmap structure */
  629. /* return value is TRUE if bitmap dimension has changed */
  630. BOOL
  631. scan_bitmap(BMAP *pbm)
  632. {
  633. PBITMAPINFO2 pbmi = pbm->pbmi;
  634. PBITMAPINFO old_pbmi = (PBITMAPINFO)pbmi;
  635. BOOL old_bmp = (pbmi->cbFix == sizeof(BITMAPINFOHEADER));
  636.  
  637.    if (old_bmp) {
  638.       /* it is a BITMAPINFO */
  639.       switch(old_pbmi->cBitCount) {
  640.         case 24:
  641.           pbm->palsize = 0;
  642.           break;
  643.         case 8:
  644.           pbm->palsize = 256;
  645.           break;
  646.         case 4:
  647.           pbm->palsize = 16;
  648.           break;
  649.         case 1:
  650.           pbm->palsize = 2;
  651.           break;
  652.         default:
  653.         pbm->valid = FALSE;
  654.           error_message("scan_bitmap: wrong number of bits"); /* panic */
  655.           return FALSE;
  656.     }
  657.     pbm->palimportant = pbm->palsize;
  658.     pbm->palsize = pbm->palsize * sizeof(RGB);
  659.         pbm->bits   = (PBYTE)old_pbmi + old_pbmi->cbFix + pbm->palsize;
  660.     pbm->width  = old_pbmi->cx;
  661.     pbm->height = old_pbmi->cy;
  662.     pbm->planes = old_pbmi->cPlanes;
  663.     pbm->depth  = old_pbmi->cBitCount;
  664.     }
  665.     else {
  666.      /* it is a BITMAPINFO2 */
  667.       switch(pbmi->cBitCount) {
  668.         case 24:
  669.           pbm->palsize = 0;
  670.           break;
  671.         case 8:
  672.           pbm->palsize = 256;
  673.           break;
  674.         case 4:
  675.           pbm->palsize = 16;
  676.           break;
  677.         case 1:
  678.           pbm->palsize = 2;
  679.           break;
  680.         default:
  681.         pbm->valid = FALSE;
  682.           error_message("scan_bitmap: wrong number of bits"); /* panic */
  683.           return FALSE;
  684.     }
  685.     if ( (pbmi->cbFix > (&(pbmi->cclrUsed) - &(pbmi->cbFix)))
  686.         && (pbmi->cclrUsed != 0) && (pbmi->cBitCount != 24) )
  687.         pbm->palsize = pbmi->cclrUsed;
  688.     pbm->palimportant = pbm->palsize;
  689.     if ( (pbmi->cbFix > (&(pbmi->cclrImportant) - &(pbmi->cbFix)))
  690.         && (pbmi->cclrImportant != 0) && (pbmi->cBitCount != 24) )
  691.         pbm->palimportant = pbmi->cclrImportant;
  692.     pbm->palsize = pbm->palsize * sizeof(RGB2);
  693.         pbm->bits   = (PBYTE)pbmi + pbmi->cbFix + pbm->palsize;
  694.     pbm->width  = pbmi->cx;
  695.     pbm->height = pbmi->cy;
  696.     pbm->planes = pbmi->cPlanes;
  697.     pbm->depth  = pbmi->cBitCount;
  698.     }
  699.  
  700.     if ((pbm->palsize != pbm->old_palsize) || (pbm->palimportant != pbm->old_palimportant)) {
  701.     if ( (pbm->depth == 8) && display.hasPalMan )
  702.         make_palette(pbm);
  703.     pbm->old_palimportant = pbm->palimportant;
  704.     }
  705.  
  706.     if ( (pbm->width   == pbm->old_width) && 
  707.          (pbm->height  == pbm->old_height) &&
  708.      (pbm->planes  == pbm->old_planes) && 
  709.      (pbm->depth   == pbm->old_depth) &&
  710.      (pbm->palsize == pbm->old_palsize) &&
  711.      (pbm->old_bmp == old_bmp) )
  712.     return FALSE;
  713.  
  714.     /* bitmap has changed */
  715.     pbm->old_width   = pbm->width;
  716.     pbm->old_height  = pbm->height;
  717.     pbm->old_planes  = pbm->planes;
  718.     pbm->old_depth   = pbm->depth;
  719.     pbm->old_palsize = pbm->palsize;
  720.     pbm->old_bmp     = old_bmp;
  721.     return TRUE;
  722. }
  723.  
  724.  
  725. void
  726. update_scroll_bars(void)
  727. {
  728.     /* Cause update of scroll bars etc. */
  729.     SWP swp;
  730.     WinQueryWindowPos(hwnd_bmp, &swp);
  731.     WinSendMsg(hwnd_bmp, WM_SIZE, MPFROM2SHORT(swp.cx, swp.cy), MPFROM2SHORT(swp.cx, swp.cy));
  732. }
  733.  
  734.  
  735. /* copy bitmap to the clipboard */
  736. void
  737. copy_clipboard(void)
  738. {
  739. HBITMAP hbmp;
  740.     if (!bitmap.valid) {
  741.     message_box("Cannot copy to clipboard:\nNo Bitmap displayed",0);
  742.     return;
  743.     }
  744.     if (WinOpenClipbrd(hab)) {
  745.     /* get bmp mutex to stop gs.exe changing bitmap while we copy it */
  746.     DosRequestMutexSem(bmp_mutex_sem, 10000);
  747.     if (scan_bitmap(&bitmap)) {
  748.         /* bitmap has changed */
  749.         update_scroll_bars();
  750.     }
  751.     hbmp = make_bitmap(&bitmap, 0, 0, bitmap.width, bitmap.height, bitmap.depth);
  752.     if (hbmp) {
  753.         WinEmptyClipbrd(hab);
  754.         WinSetClipbrdData(hab, (ULONG)hbmp, CF_BITMAP, CFI_HANDLE);
  755.     }
  756.     
  757.     DosReleaseMutexSem(bmp_mutex_sem);
  758.     WinCloseClipbrd(hab);
  759.     }
  760. }
  761.  
  762.  
  763. HBITMAP
  764. make_bitmap(BMAP *pbm, ULONG left, ULONG bottom, ULONG right, ULONG top, ULONG depth)
  765. {
  766. HDC hdc = DEV_ERROR, hdcMem = DEV_ERROR;
  767. HPS hps = GPI_ERROR;
  768. HBITMAP hbmp = GPI_ERROR, hbmr = HBM_ERROR;
  769. SIZEL sizePS;
  770. BITMAPINFOHEADER2 bmih;
  771.  
  772.     if ( (left == right) || (bottom == top) )
  773.         return (HBITMAP)NULL;
  774.  
  775.     if (right > pbm->width)
  776.         right = pbm->width;
  777.     if (left > pbm->width)
  778.         left = 0;
  779.     if (top > pbm->height)
  780.         top = pbm->height;
  781.     if (bottom > pbm->height)
  782.         bottom = 0;
  783.         
  784.     memset(&bmih, 0, sizeof(bmih));
  785.     bmih.cbFix = sizeof(BITMAPINFOHEADER2);
  786.     bmih.cx = right - left;
  787.     bmih.cy = top - bottom;
  788.     bmih.cPlanes = 1;
  789.     bmih.cBitCount = depth;
  790.  
  791.     /* create memory DC compatible with screen */
  792.     hdcMem = DevOpenDC(hab, OD_MEMORY, "*", 0L, NULL, NULLHANDLE);
  793.  
  794.     sizePS.cx = right - left;
  795.     sizePS.cy = top - bottom;
  796.     if (hdcMem != DEV_ERROR)
  797.         hps = GpiCreatePS(hab, hdcMem, &sizePS, 
  798.         PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC );
  799.  
  800.     if (hps != GPI_ERROR)
  801.         hbmp = GpiCreateBitmap(hps, &bmih, 0L, NULL, NULL);
  802.  
  803.     if (hbmp != GPI_ERROR)
  804.         hbmr = GpiSetBitmap(hps, hbmp);
  805.  
  806.  
  807.     if (hbmr != HBM_ERROR) {
  808.         LONG rc;
  809.         ERRORID eid;
  810.               POINTL apts[4];
  811.         /* target is inclusive */
  812.         apts[0].x = 0;
  813.         apts[0].y = 0;
  814.         apts[1].x = right - left - 1;
  815.         apts[1].y = top - bottom - 1;
  816.         /* source is not inclusive of top & right borders */
  817.         apts[2].x = left;
  818.         apts[2].y = bottom;
  819.         apts[3].x = right;
  820.         apts[3].y = top;
  821.  
  822.         rc = 0;
  823.         eid = WinGetLastError(hab);
  824.             rc = GpiDrawBits(hps, pbm->bits, pbm->pbmi, 4, apts, 
  825.             (bitmap.depth != 1) ? ROP_SRCCOPY : ROP_NOTSRCCOPY, 0);
  826.         if (rc==0) {
  827.             char buf[256];
  828.             eid = WinGetLastError(hab);
  829.             sprintf(buf,"make_bitmap: GpiDrawBits rc = %08x, eid = %08x",rc, eid);
  830.             message_box(buf, 0);
  831.         }
  832.     }
  833.     
  834.     if (hbmr != HBM_ERROR)
  835.         GpiSetBitmap(hps, (ULONG)0);
  836.     if (hps != GPI_ERROR)
  837.         GpiDestroyPS(hps);
  838.     if (hdcMem != DEV_ERROR)
  839.         DevCloseDC(hdcMem);
  840.  
  841.     if ( (hbmr == HBM_ERROR) || (hdcMem == DEV_ERROR) ||
  842.         (hbmp == GPI_ERROR) || (hps == GPI_ERROR) ) {
  843.         if (hbmp != GPI_ERROR)
  844.             GpiDeleteBitmap(hbmp);
  845.         debugbeep(2);
  846.         return 0;
  847.     }
  848.     return hbmp;
  849. }
  850.  
  851. MRESULT
  852. paint_bitmap(HPS ps, PRECTL prect, int scrollx, int scrolly)
  853. {
  854.     POINTL apts[4];
  855.     int wx, wy;
  856.     if (WinIsRectEmpty(hab, prect))
  857.     return 0;
  858.     if (ps == NULLHANDLE) {
  859.     debugbeep(1);
  860.     }
  861.     /* source is not inclusive of top & right borders */
  862.     wx = prect->xRight - prect->xLeft; /* update width */
  863.     wy = prect->yTop - prect->yBottom; /* update height */
  864.     apts[2].x   = prect->xLeft + scrollx;
  865.     apts[2].y = prect->yBottom + scrolly;
  866.     if (apts[2].x > bitmap.width)
  867.         apts[2].x = bitmap.width;
  868.     if (apts[2].x + wx > bitmap.width)
  869.         wx = bitmap.width - apts[2].x;
  870.     apts[3].x = apts[2].x + wx;
  871.     if (apts[2].y > bitmap.height)
  872.         apts[2].y = bitmap.height;
  873.     if (apts[2].y + wy > bitmap.height)
  874.         wy = bitmap.height - apts[2].y;
  875.     apts[3].y = apts[2].y + wy;
  876.     /* target is inclusive */
  877.     apts[0].x = prect->xLeft;
  878.     apts[0].y = prect->yBottom;
  879.     apts[1].x = prect->xLeft + wx - 1;
  880.     apts[1].y = prect->yBottom + wy - 1;
  881.  
  882.     if ( (display.bitcount == 4)  /* standard VGA is buggy */
  883.     || ( (os_version==201100) && (display.bitcount==8) && (bitmap.depth==1)) /* S3 and ATI GU are buggy */
  884.          ) {
  885.     /* slow code to dodge OS/2 bugs */
  886.     /* this code double buffers the bitmap and works on a standard VGA
  887.      * but didn't work on an ATI Ultra Graphics Pro in 8514 emulation
  888.      */
  889.     /* This won't work for version 2.11, S3 or ATI GU, 8bit/pixel display, 8bit/pixel bitmap */
  890.     HBITMAP hbmp;
  891.     /* create a bitmap */
  892.     hbmp = make_bitmap(&bitmap, apts[2].x, apts[2].y, apts[3].x, apts[3].y, bitmap.depth);
  893.     /* Draw it to the display */
  894.     if (hbmp) {
  895.         WinDrawBitmap(ps, hbmp, NULL, &apts[0], CLR_BLACK, CLR_WHITE, DBM_NORMAL);
  896.         GpiDeleteBitmap(hbmp);
  897.     }
  898.     }
  899.     else {
  900.     /* fast code which doesn't always work */
  901.     /* This code works on the Trident SVGA and 8514 in 256 color mode,
  902.       * but GpiDrawBits fails with a SYS3175 on the standard VGA.
  903.      */
  904.     /* This won't work for version 2.11, S3 or ATI GU, 8bit/pixel display, 1bit/pixel bitmap */
  905.     GpiDrawBits(ps, bitmap.bits, bitmap.pbmi, 4, apts, 
  906.         (bitmap.depth != 1) ? ROP_SRCCOPY : ROP_NOTSRCCOPY, 0);
  907.     }
  908.  
  909.     return 0;
  910. }
  911.  
  912.  
  913. /* This is the window function */
  914. MRESULT EXPENTRY ClientWndProc(HWND hwnd, ULONG mess, 
  915.             MPARAM mp1, MPARAM mp2)
  916. {
  917.   char buf[256];
  918.   static int cxClient, cyClient;
  919.   static int cxAdjust, cyAdjust;
  920.   static int nHscrollMax, nHscrollPos;
  921.   static int nVscrollMax, nVscrollPos;
  922.   int nHscrollInc;
  923.   int nVscrollInc;
  924.   HWND hwndScroll;
  925.   HPS hps;
  926.   RECTL rect;
  927.   ULONG ulclr;
  928.  
  929.     switch(mess) {
  930.     case WM_CREATE:
  931.         break;
  932.     case WM_ERASEBACKGROUND:
  933.         /* by returning TRUE, the Presentation Manager automatically clears
  934.          * the window each time the window is resized or moved.
  935.          */
  936.         return (MRESULT)TRUE;
  937.     case WM_GSUPDATE:
  938.          if (!WinInvalidateRect(hwnd_bmp, (PRECTL)NULL, TRUE))
  939.             error_message("error invalidating rect");
  940.            if (!WinUpdateWindow(hwnd_bmp))
  941.             error_message("error updating window");
  942.          return 0;
  943.     case WM_COMMAND:
  944.         switch(LONGFROMMP(mp1)) {
  945.         case IDM_ABOUT:
  946.             WinDlgBox(HWND_DESKTOP, hwnd, AboutDlgProc, 0, IDD_ABOUT, 0);
  947.             break;
  948.         case IDM_COPY:
  949.             copy_clipboard();
  950.             break;
  951.         }
  952.         break;
  953.     case WM_REALIZEPALETTE:
  954.         if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) {
  955.         hps = WinGetPS(hwnd);
  956.         if (hps == NULLHANDLE)
  957.             debugbeep(1);
  958.         GpiSelectPalette(hps, display.hpal);
  959.             if (WinRealizePalette(hwnd, hps, &ulclr) > 0)
  960.             WinInvalidateRect(hwnd, NULL, FALSE);
  961.         GpiSelectPalette(hps, (HPAL)NULL);
  962.         WinReleasePS(hps);
  963.             return 0;
  964.         }
  965.         break;    /* use default processing */
  966.     case WM_PAINT:
  967.         /* Refresh the window each time the WM_PAINT message is received */
  968.  
  969.         /* get bmp mutex to stop gs.exe changing bitmap while we paint */
  970.         DosRequestMutexSem(bmp_mutex_sem, 10000);
  971.         if (scan_bitmap(&bitmap))
  972.         update_scroll_bars(); /* bitmap has changed */
  973.  
  974.         if (!bitmap.valid) {
  975.             DosReleaseMutexSem(bmp_mutex_sem);
  976.             hps = WinBeginPaint(hwnd, (ULONG)0, &rect);
  977.             if (hps == NULLHANDLE)
  978.             debugbeep(4);
  979.         WinFillRect(hps, &rect, CLR_BACKGROUND);
  980.         WinEndPaint(hwnd);
  981.         return 0;
  982.         }
  983.  
  984.         hps = WinBeginPaint(hwnd, (HPS)NULL, &rect);
  985.         if (hps == NULLHANDLE)
  986.         debugbeep(4);
  987.         if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) {
  988.             GpiSelectPalette(hps, display.hpal);
  989.                 WinRealizePalette(hwnd, hps, &ulclr);
  990.             paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
  991.             GpiSelectPalette(hps, (HPAL)NULL);
  992.         }
  993.         else
  994.             paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
  995.         WinEndPaint(hwnd);
  996.  
  997.         DosReleaseMutexSem(bmp_mutex_sem);
  998.         return 0;
  999.     case WM_MOVE:
  1000.         /* don't interrogate the window location immediately since */
  1001.         /* it causes the Diamond Stealth VL24 with IBM S3 drivers */
  1002.         /* to corrupt the display */
  1003.         DosSleep(50);
  1004.         if (hwnd_frame) {  /* save window position for INI file */
  1005.         SWP swp;
  1006.         WinQueryWindowPos(WinQueryWindow(hwnd, QW_PARENT), &swp);
  1007.         if (!(swp.fl & SWP_MINIMIZE)) {
  1008.             option.img_origin.x = swp.x;
  1009.             option.img_origin.y = swp.y;
  1010.             option.img_max = ((swp.fl & SWP_MAXIMIZE) != 0);
  1011.         }
  1012.         }
  1013.         return 0;
  1014.     case WM_SIZE:
  1015.         cyClient = SHORT2FROMMP(mp2);
  1016.         cxClient = SHORT1FROMMP(mp2);
  1017.  
  1018.         cyAdjust = min(bitmap.height, cyClient) - cyClient;
  1019.         cyClient += cyAdjust;
  1020.  
  1021.         nVscrollMax = max(0, bitmap.height - cyClient);
  1022.         nVscrollPos = min(nVscrollPos, nVscrollMax);
  1023.         scroll_pos.y = nVscrollMax - nVscrollPos;
  1024.  
  1025.         if (!bitmap.valid)
  1026.             cyClient = cyAdjust = nVscrollMax = nVscrollPos;
  1027.  
  1028.         hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_VERTSCROLL);
  1029.         WinSendMsg(hwndScroll, SBM_SETSCROLLBAR, MPFROMLONG(nVscrollPos), 
  1030.             MPFROM2SHORT(0, nVscrollMax));
  1031.         if (bitmap.valid)
  1032.             WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(cyClient, bitmap.height),
  1033.             MPFROMLONG(0));
  1034.         else
  1035.             WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(1, 1),
  1036.             MPFROMLONG(0));
  1037.  
  1038.         cxAdjust = min(bitmap.width,  cxClient) - cxClient;
  1039.         cxClient += cxAdjust;
  1040.  
  1041.         nHscrollMax = max(0, bitmap.width - cxClient);
  1042.         nHscrollPos = min(nHscrollPos, nHscrollMax);
  1043.         scroll_pos.x = nHscrollPos;
  1044.  
  1045.         if (!bitmap.valid)
  1046.             cxClient = cxAdjust = nHscrollMax = nHscrollPos;
  1047.  
  1048.         hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_HORZSCROLL);
  1049.         WinSendMsg(hwndScroll, SBM_SETSCROLLBAR, MPFROMLONG(nHscrollPos), 
  1050.             MPFROM2SHORT(0, nHscrollMax));
  1051.         if (bitmap.valid)
  1052.             WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(cxClient, bitmap.width),
  1053.             MPFROMLONG(0));
  1054.         else
  1055.             WinSendMsg(hwndScroll, SBM_SETTHUMBSIZE, MPFROM2SHORT(1, 1),
  1056.             MPFROMLONG(0));
  1057.  
  1058.         if ((cxAdjust!=0 || cyAdjust!=0)) {
  1059.             SWP swp;
  1060.             WinQueryWindowPos(WinQueryWindow(hwnd, QW_PARENT), &swp);
  1061.             WinSetWindowPos(WinQueryWindow(hwnd, QW_PARENT), 0, 
  1062.             swp.x, swp.y - cyAdjust,
  1063.             swp.cx + cxAdjust, swp.cy + cyAdjust, SWP_SIZE | SWP_MOVE);
  1064.             cxAdjust = cyAdjust = 0;
  1065.         }
  1066.             if (hwnd_frame) { /* save window size for INI file */
  1067.             SWP swp;
  1068.             WinQueryWindowPos(WinQueryWindow(hwnd, QW_PARENT), &swp);
  1069.             if (!(swp.fl & SWP_MINIMIZE)) {
  1070.                 option.img_size.x = swp.cx;
  1071.                 option.img_size.y = swp.cy;
  1072.                 option.img_max = ((swp.fl & SWP_MAXIMIZE) != 0);
  1073.             }
  1074.         }
  1075.         break;
  1076.     case WM_VSCROLL:
  1077.         switch(SHORT2FROMMP(mp2)) {
  1078.         case SB_LINEUP:
  1079.             nVscrollInc = -cyClient/16;
  1080.             break;
  1081.         case SB_LINEDOWN:
  1082.             nVscrollInc = cyClient/16;
  1083.             break;
  1084.         case SB_PAGEUP:
  1085.             nVscrollInc = min(-1,-cyClient);
  1086.             break;
  1087.         case SB_PAGEDOWN:
  1088.             nVscrollInc = max(1,cyClient);
  1089.             break;
  1090.         case SB_SLIDERPOSITION:
  1091.             nVscrollInc = SHORT1FROMMP(mp2) - nVscrollPos;
  1092.             break;
  1093.         case SB_TOP:
  1094.             nVscrollInc = -nVscrollPos;
  1095.             break;
  1096.         case SB_BOTTOM:
  1097.             nVscrollInc = nVscrollMax - nVscrollPos;
  1098.             break;
  1099.         default:
  1100.             nVscrollInc = 0;
  1101.         }
  1102.         if ((nVscrollInc = max(-nVscrollPos, 
  1103.         min(nVscrollInc, nVscrollMax - nVscrollPos)))!=0) {
  1104.         LONG lComplexity;
  1105.         hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_VERTSCROLL);
  1106.         nVscrollPos += nVscrollInc;
  1107.         scroll_pos.y = nVscrollMax - nVscrollPos;
  1108.         lComplexity = WinScrollWindow(hwnd, 0, nVscrollInc, (PRECTL)NULL, (PRECTL)NULL, 
  1109.             (HRGN)NULLHANDLE, (PRECTL)&rect, 0);
  1110.         WinSendMsg(hwndScroll, SBM_SETPOS, MPFROMLONG(nVscrollPos), 0);
  1111.         if (lComplexity != RGN_RECT) {
  1112.             WinInvalidateRect(hwnd, (PRECTL)NULL, FALSE);
  1113.             WinUpdateWindow(hwnd);
  1114.         }
  1115.         else {
  1116.             /* redraw exposed area */
  1117.             hps = WinGetPS(hwnd);
  1118.             if (hps == NULLHANDLE)
  1119.             debugbeep(1);
  1120.                 if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) {
  1121.                     GpiSelectPalette(hps, display.hpal);
  1122.                         WinRealizePalette(hwnd, hps, &ulclr);
  1123.                 paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
  1124.                     GpiSelectPalette(hps, (HPAL)NULL);
  1125.                 }
  1126.             else
  1127.                 paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
  1128.             WinReleasePS(hps);
  1129.         }
  1130.         }
  1131.         break;
  1132.     case WM_HSCROLL:
  1133.         switch(SHORT2FROMMP(mp2)) {
  1134.         case SB_LINELEFT:
  1135.             nHscrollInc = -cxClient/16;
  1136.             break;
  1137.         case SB_LINERIGHT:
  1138.             nHscrollInc = cyClient/16;
  1139.             break;
  1140.         case SB_PAGELEFT:
  1141.             nHscrollInc = min(-1,-cxClient);
  1142.             break;
  1143.         case SB_PAGERIGHT:
  1144.             nHscrollInc = max(1,cxClient);
  1145.             break;
  1146.         case SB_SLIDERPOSITION:
  1147.             nHscrollInc = SHORT1FROMMP(mp2) - nHscrollPos;
  1148.             break;
  1149.         default:
  1150.             nHscrollInc = 0;
  1151.         }
  1152.         if ((nHscrollInc = max(-nHscrollPos, 
  1153.         min(nHscrollInc, nHscrollMax - nHscrollPos)))!=0) {
  1154.         LONG lComplexity;
  1155.         hwndScroll = WinWindowFromID(WinQueryWindow(hwnd, QW_PARENT), FID_HORZSCROLL);
  1156.         nHscrollPos += nHscrollInc;
  1157.         scroll_pos.x = nHscrollPos;
  1158.         lComplexity = WinScrollWindow(hwnd, -nHscrollInc, 0, (PRECTL)NULL, (PRECTL)NULL, 
  1159.             (HRGN)NULLHANDLE, (PRECTL)&rect, 0);
  1160.         /* need to send next message BEFORE redrawing, otherwise S3 driver screws up */
  1161.         WinSendMsg(hwndScroll, SBM_SETPOS, MPFROMLONG(nHscrollPos), 0);
  1162.         if (lComplexity != RGN_RECT) {
  1163.             WinInvalidateRect(hwnd, (PRECTL)NULL, FALSE);
  1164.             WinUpdateWindow(hwnd);
  1165.         }
  1166.         else {
  1167.             /* redraw exposed area */
  1168.             hps = WinGetPS(hwnd);
  1169.             if (hps == NULLHANDLE)
  1170.             debugbeep(1);
  1171.                 if ((bitmap.depth == 8) && display.hasPalMan && display.hpal_exists) {
  1172.                     GpiSelectPalette(hps, display.hpal);
  1173.                         WinRealizePalette(hwnd, hps, &ulclr);
  1174.                 paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
  1175.                     GpiSelectPalette(hps, (HPAL)NULL);
  1176.                 }
  1177.             else
  1178.                 paint_bitmap(hps, &rect, nHscrollPos, nVscrollMax - nVscrollPos);
  1179.             WinReleasePS(hps);
  1180.         }
  1181.         }
  1182.         break;
  1183.     case WM_CHAR:    /* process keystrokes here */
  1184.         if (SHORT1FROMMP(mp1) & KC_CHAR) {
  1185.         /* pass control to gs if ENTER pressed */
  1186.         if (hwnd_gs && (SHORT1FROMMP(mp2) == '\r'))
  1187.             WinSetActiveWindow(HWND_DESKTOP, hwnd_gs);
  1188.         }
  1189.         /* Process only key presses, not key releases */
  1190.         if (SHORT1FROMMP(mp1) & KC_KEYUP)
  1191.         break;
  1192.         if (SHORT1FROMMP(mp1) & KC_VIRTUALKEY) {
  1193.         USHORT vkey = SHORT2FROMMP(mp2);
  1194.         switch(vkey) {
  1195.             case VK_HOME:
  1196.                 WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_TOP));
  1197.                 break;
  1198.             case VK_END:
  1199.                 WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_BOTTOM));
  1200.                 break;
  1201.             case VK_UP:
  1202.                 WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINEUP));
  1203.                 break;
  1204.             case VK_DOWN:
  1205.                 WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINEDOWN));
  1206.                 break;
  1207.             case VK_PAGEUP:
  1208.                 WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGEUP));
  1209.                 break;
  1210.             case VK_PAGEDOWN:
  1211.                 WinSendMsg(hwnd, WM_VSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGEDOWN));
  1212.                 break;
  1213.             case VK_LEFT:
  1214.                 if (SHORT1FROMMP(mp1) & KC_CTRL)
  1215.                     WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGELEFT));
  1216.               else
  1217.                     WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINELEFT));
  1218.                 break;
  1219.             case VK_RIGHT:
  1220.                 if (SHORT1FROMMP(mp1) & KC_CTRL)
  1221.                     WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_PAGERIGHT));
  1222.                 else
  1223.                     WinSendMsg(hwnd, WM_HSCROLL, MPFROMLONG(0), MPFROM2SHORT(0, SB_LINERIGHT));
  1224.                 break;
  1225.         }
  1226.         }
  1227.         break;
  1228.     default:
  1229.         /* All messages not handled by the ClientWndProc must be passed
  1230.          * along to the Presentation Manager for default processing
  1231.          */
  1232.         return WinDefWindowProc(hwnd, mess, mp1, mp2);
  1233.   }
  1234.   return (MRESULT)FALSE;
  1235. }
  1236.  
  1237.  
  1238.  
  1239. /* About Dialog Box */
  1240. MRESULT EXPENTRY AboutDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1241. {
  1242.   switch(msg) {
  1243.     case  WM_COMMAND:
  1244.       switch(COMMANDMSG(&msg)->cmd) {
  1245.     case DID_OK:
  1246.           WinDismissDlg(hwnd, TRUE);
  1247.           return (MRESULT)TRUE;
  1248.       }
  1249.       break;
  1250.   }
  1251.   return WinDefDlgProc(hwnd, msg, mp1, mp2);
  1252. }    
  1253.